package com.meida.base.provider.controller.api;

import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.google.common.collect.Maps;
import com.meida.base.provider.service.GiteeAuthServiceImpl;
import com.meida.base.provider.service.QQAuthServiceImpl;
import com.meida.base.provider.service.WechatAuthServiceImpl;
import com.meida.common.base.handler.AdminLoginHandler;
import com.meida.common.base.handler.AdminUserInfoHandler;
import com.meida.common.base.module.LoginParams;
import com.meida.common.mybatis.model.ResultBody;
import com.meida.common.oauth2.OpenOAuth2ClientDetails;
import com.meida.common.oauth2.OpenOAuth2ClientProperties;
import com.meida.common.security.OpenHelper;
import com.meida.common.security.OpenUser;
import com.meida.common.base.utils.FlymeUtils;
import com.meida.common.utils.SpringContextHolder;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerEndpointsConfiguration;
import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;
import org.springframework.web.bind.annotation.*;

import java.security.Principal;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

/**
 * @author: zyf
 * @date: 2018/11/9 15:43
 * @description:
 */
@Api(tags = "认证开放")
@RestController
public class ApiController {
    @Autowired
    private QQAuthServiceImpl qqAuthService;
    @Autowired
    private WechatAuthServiceImpl wechatAuthService;
    @Autowired
    private GiteeAuthServiceImpl giteeAuthService;


    @Autowired
    private RedisTokenStore tokenStore;

    @Autowired
    private OpenOAuth2ClientProperties clientProperties;

    @Autowired
    AuthorizationServerEndpointsConfiguration endpoints;



    @Autowired(required = false)
    private AdminUserInfoHandler adminUserInfoHandler;

    /**
     * 获取用户基础信息
     *
     * @return
     */
    @ApiOperation(value = "获取用户基础信息")
    @GetMapping("/current/user")
    public ResultBody getUserProfile() {
        OpenUser user = OpenHelper.getUser();
        if (FlymeUtils.isNotEmpty(adminUserInfoHandler)) {
            adminUserInfoHandler.initOpenUser(user);
        }

        return ResultBody.ok(user);
    }

    /**
     * 获取当前登录用户信息-SSO单点登录
     *
     * @param principal
     * @return
     */
    @ApiOperation(value = "获取当前登录用户信息-SSO单点登录", notes = "获取当前登录用户信息-SSO单点登录")
    @GetMapping("/current/user/sso")
    public Principal principal(Principal principal) {
        return principal;
    }
    /*
     */
/**
 * 获取用户访问令牌
 * 基于oauth2密码模式登录
 *
 * @param username
 * @param password
 * @return access_token
 *//*

    @ApiOperation(value = "获取用户访问令牌", notes = "基于oauth2密码模式登录,无需签名,返回access_token")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "username", required = true, value = "登录名", paramType = "form"),
            @ApiImplicitParam(name = "password", required = true, value = "登录密码", paramType = "form")
    })
    @PostMapping("/login/token")
    public Object getLoginToken(@RequestParam String username, @RequestParam String password, @RequestHeader HttpHeaders headers) {
        // 使用oauth2密码模式登录.
        MultiValueMap<String, Object> postParameters = new LinkedMultiValueMap<>();
        postParameters.add("username", username);
        postParameters.add("password", password);
        postParameters.add("client_id", resourceDetails.getClientId());
        postParameters.add("client_secret", resourceDetails.getClientSecret());
        postParameters.add("grant_type", "password");
        // 使用客户端的请求头,发起请求
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        // 强制移除 原来的请求头,防止token失效
        headers.remove(HttpHeaders.AUTHORIZATION);
        HttpEntity<MultiValueMap<String, Object>> request = new HttpEntity(postParameters, headers);
        Map result = openRestTemplate.postForObject(resourceDetails.getAccessTokenUri(), request, Map.class);
        if (result.containsKey("access_token")) {
            return ResultBody.ok().data(result);
        } else {
            return result;
        }
    }
*/


    /**
     * 获取用户访问令牌
     * 基于oauth2密码模式登录
     *
     * @param username
     * @param password
     * @return access_token
     */
    @ApiOperation(value = "登录接口", notes = "基于oauth2密码模式登录,无需签名,返回access_token")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "username", required = true, value = "登录名", paramType = "form"),
            @ApiImplicitParam(name = "password", required = true, value = "登录密码", paramType = "form")
    })
    @PostMapping("/login/token")
    public ResultBody getLoginToken(LoginParams loginParams) throws Exception {
        return getToken(loginParams, null);
    }

    /**
     * 退出移除令牌
     *
     * @param token
     */
    @ApiOperation(value = "退出移除令牌", notes = "退出移除令牌")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "token", required = true, value = "访问令牌", paramType = "form")
    })
    @PostMapping("/logout/token")
    public ResultBody removeToken(@RequestParam String token) {
        tokenStore.removeAccessToken(tokenStore.readAccessToken(token));
        return ResultBody.ok();
    }


    /**
     * 获取第三方登录配置
     *
     * @return
     */
    @ApiOperation(value = "获取第三方登录配置", notes = "任何人都可访问")
    @GetMapping("/login/config")
    @ResponseBody
    public ResultBody getLoginOtherConfig() {
        Map<String, String> map = Maps.newHashMap();
        map.put("qq", qqAuthService.getAuthorizationUrl());
        map.put("wechat", wechatAuthService.getAuthorizationUrl());
        map.put("gitee", giteeAuthService.getAuthorizationUrl());
        return ResultBody.ok(map);
    }


    /**
     * 生成 oauth2 token
     *
     * @param userName
     * @param password
     * @param type
     * @return
     */
    public ResultBody getToken(LoginParams loginParams, String type) throws Exception {
        ResultBody resultBody = new ResultBody();
        AdminLoginHandler loginHandler = SpringContextHolder.getHandler(loginParams.getHandlerName(), AdminLoginHandler.class);
        Boolean hanHandler = false;
        if (ObjectUtils.isNotEmpty(loginHandler)) {
            hanHandler = true;
            //执行校验
            resultBody = loginHandler.beforLogin(loginParams);
        }
        OpenOAuth2ClientDetails clientDetails = clientProperties.getOauth2().get("admin");
        // 使用oauth2密码模式登录.
        Map<String, String> postParameters = new HashMap<>();
        postParameters.put("username", loginParams.getUsername());
        postParameters.put("password", loginParams.getPassword());
        postParameters.put("client_id", clientDetails.getClientId());
        postParameters.put("client_secret", clientDetails.getClientSecret());
        postParameters.put("grant_type", "password");
        // 添加参数区分,第三方登录
        postParameters.put("login_type", type);
        OAuth2AccessToken oAuth2AccessToken = OpenHelper.createAccessToken(endpoints, postParameters);
        Map<String, Object> map = new HashMap<>(16);
        if (ObjectUtils.isNotEmpty(oAuth2AccessToken)) {
            map.put("access_token", "Bearer " + oAuth2AccessToken.getValue());
            map.put("token_type", oAuth2AccessToken.getTokenType());
            map.put("expires_in", oAuth2AccessToken.getExpiresIn());
            map.put("refresh_token", Optional.ofNullable(oAuth2AccessToken.getRefreshToken()).orElse(() -> "").getValue());
            map.putAll(oAuth2AccessToken.getAdditionalInformation());
            if (hanHandler) {
                loginHandler.afterLogin(map, loginParams);
            }
            resultBody.data(map);
        }
        return resultBody;
    }

}
